/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  BaseString.h
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2016/01/12
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#pragma once

#include "../core.h"
#include "TinyString.h"

namespace qb {
namespace base {
template <typename T>
class StackArrayImpl {
 protected:
  T* m_ptr;       // 指向堆上的数据,有可能与m_buf相等
  int m_capcity;  // 堆内存m_ptr的实际空间大小
  int m_size;     // 对内存m_ptr或者栈内存m_buf中装载的数据大小
  T* m_buf;       // 指向栈上的数据
 public:
  StackArrayImpl() : m_size(0), m_capcity(0), m_ptr(NULL), m_buf(NULL) {}
  StackArrayImpl(T* buf, int capcity)
      : m_size(0), m_capcity(capcity), m_ptr(buf), m_buf(buf) {}
  ~StackArrayImpl() {
    if (m_ptr && m_ptr != m_buf) delete[] m_ptr;
  }
  void Add(const T& T1) { Add(&T1, 1); }
  void Add(const T* buf, int size) {
    if (buf == 0) return;
    if (sizeof(T) == sizeof(char)) {
      size = size <= 0 ? strlen((const char*)buf) : size;
    }
    if (size <= 0) return;
    if (m_ptr == m_buf && m_size + size < m_capcity) {
      memcpy(m_buf + m_size, buf, size * sizeof(T));
      m_size += size;
    } else {
      int extra = size + 1;
      int half = m_size / 2;
      int plus = extra < half ? half : extra;
      T* mem = new T[m_size + plus];
      memcpy(mem, m_ptr, m_size * sizeof(T));
      memcpy(mem + m_size, buf, size * sizeof(T));
      memset(mem + m_size + size, 0, (plus - size) * sizeof(T));
      if (m_ptr && m_ptr != m_buf) delete[] m_ptr;
      m_ptr = mem;
      m_capcity = m_size + plus - 1;
      m_size = m_size + size;
    }
  }

  operator const T*() const { return m_ptr; }
  operator T*() { return m_ptr; }
  int size() const { return m_size; }
  T* GetBuf() { return m_ptr; }
  const T& at(int pos) const { return m_ptr[pos]; }
  T& at(int pos) { return m_ptr[pos]; }

 protected:
  void SetSizeImpl(int size, int N) {
    if (m_ptr != m_buf)  // 堆
    {
      if (size > N) {
        if (size > m_capcity) {
          if (m_ptr) delete[] m_ptr;
          m_ptr = new T[size];
          m_capcity = size;
        }
        m_size = size;
        memset(m_ptr, 0, sizeof(T) * m_capcity);
      } else {
        if (m_ptr) delete[] m_ptr;
        m_ptr = m_buf;
        m_capcity = N;
        m_size = size;
      }
    } else {
      m_capcity = N;
      m_size = size;
    }
  }
  void Clear() {
    // 清除,以便可以再装载,复用内存
    m_size = 0;
    if (m_ptr && m_ptr != m_buf && m_capcity > 0) memset(m_ptr, 0, m_capcity);
  }
};
template <typename T, int N>
class StackArray
    : public StackArrayImpl<
          T> {  // 当加入的内容小于N，那么在栈上分配,超过配额在堆上分配
  T m_real_buf[N];  //
 public:
  StackArray() {
    memset(m_real_buf, 0, sizeof(T) * N);
    StackArrayImpl<T>::m_capcity = N;
    StackArrayImpl<T>::m_buf = m_real_buf;
    StackArrayImpl<T>::m_ptr = m_real_buf;
  }
  int StackCapcity() const { return N; }
  void Reset() {
    memset(m_real_buf, 0, sizeof(T) * N);
    StackArrayImpl<T>::Clear();
  }
  void SetSize(int size) {
    memset(m_real_buf, 0, sizeof(T) * N);
    StackArrayImpl<T>::SetSizeImpl(size, N);
  }
};
class S_CORE_EXPORT BaseString {
 public:
  typedef BaseString ThisType;
  typedef char Element;
  enum { INIT_CAPCITY = 16, npos = -1 };

 protected:
  int m_size;
  int m_capcity;
  Element* m_string;
  Element m_null[2];

 public:  // constructors
  BaseString();
  BaseString(int capcity);
  BaseString(const Element* str);
  BaseString(const Element* str, int len);
  BaseString(const ThisType& bs);
  ~BaseString();

  BaseString(BaseString&& bs);
  BaseString& operator=(BaseString&& bs);

  ThisType& operator=(const Element* str);
  ThisType& operator=(const ThisType& bs);
  ThisType& operator=(Element c);
  void expand(int size);
  static inline int length(const Element* str) { return str ? strlen(str) : 0; }

 public:  // operations
  void clear();
  void reset();

  ThisType& assign(Element c);
  ThisType& assign(const Element* str);
  ThisType& assign(const Element* str, int len);
  ThisType& assign(const ThisType& br);

  ThisType& append(Element c);
  ThisType& append(int count, Element c);
  ThisType& append(const Element* str);
  ThisType& append(const Element* str, int len);
  ThisType& append(const ThisType& br);

  ThisType& push_back(Element c);
  ThisType& push_back(const Element* str);
  ThisType& push_back(const Element* str, int len);
  ThisType& push_back(const ThisType& br);

  ThisType& insert(int pos, const Element* str, int len);
  ThisType& erase(int pos, int len = 1);

  ThisType& replace(int pos, int len, const Element* str, int size);
  int find(Element c, int offset = 0) const;
  int find(const Element* str, int offset = 0) const;
  int rfind(Element c, int offset = 0) const;
  void substr(int offset, int len, ThisType& bs) const;
  ThisType substr(int offset, int len) const;
  int compare(const Element* str, int len) const;
  void swap(ThisType& bs);

 public:  // operators
  // ThisType& operator+(const ThisType& bs){return append(bs);}
  // ThisType& operator+(const Element c){return append(c);}
  ThisType operator+(const ThisType& bs) const {
    ThisType ret(*this);
    ret.append(bs);
    return ret;
  }

  bool operator==(const ThisType& bs) const {
    return compare(bs.m_string, bs.m_size) == 0;
  }
  bool operator==(const Element* str) const {
    return compare(str, length(str)) == 0;
  }
  bool operator!=(const ThisType& bs) const {
    return compare(bs.m_string, bs.m_size) != 0;
  }
  bool operator!=(const Element* str) const {
    return compare(str, length(str)) != 0;
  }

 public:  // accessors
  const Element* c_str() const {
    return (m_string != 0 && m_size > 0) ? m_string : m_null;
  }
  Element* c_str() { return (m_string != 0 && m_size > 0) ? m_string : m_null; }
  operator const Element*() const { return c_str(); }
  int size() const { return m_size; }
  int capcity() const { return m_capcity; }
  bool empty() const { return !m_string || m_size <= 0; }
  Element at(int i) const;
  Element& at(int i);
  Element operator[](int i) const { return at(i); }
  Element& operator[](int i) { return at(i); }
  static int SearchString(const Element* mainStr, int mainStrLen,
                          const Element* subStr, int subStrLen, bool ic);
};

S_CORE_EXPORT BaseString& operator+=(BaseString& bs,
                                     const BaseString::Element* str);
S_CORE_EXPORT BaseString& operator+=(BaseString& bs, const BaseString& plus);
S_CORE_EXPORT bool operator<(const BaseString& left, const BaseString& right);

/*
        KeyString 主要用于std::map的first参数,用于降低内存开销
        尤其是对于平均长度<=3  或者平均长度>=15

        取n为字符串长度,总共需要的内存由如下关系:
                                n<=3   n<=15    n<=255   n<=65536
        std::string 24     24       n+25     n+25
        KeyString   4      n+6      n+6      n+7
        当长度<=15的情况下,越接近15,相对于std::string,KeyString节省的内存越少
                长度越小节省越多
        长度>=16,总是比std::string节省19个字节,节省与长度无关

        如何针对只有1-2个字符的字符串进行优化编码???
        考虑到在32平台下,指针的最高位始终为0,有效虚拟地址空间为0-2g(2^31)
        因此,把31位当做模式,当为1,表示指针模式,为0,表示编码模式

        KeyString 可以处于两种模式
                指针模式
   m_data的最高位为1,低31位构成一个指针,指向超过3个字符的字符串
                                        并且m_data指向的内容中,开头1-2个字节,表示长度
                                        第一个字节的最高位如果为1,长度用2个字节表示
                                        第一个字节的最高位如果为0,长度用1个字节表示
                                        指针模式下,内存占用为4+1/2+字符串长度+1个字节零结尾
                编码模式
   m_data的最高位为0,m_raw为一个数组,m_raw[3]为0,同时31位也为0
                                        编码模式下,内存占用为4个字节

        劣势:
                当一般的函数参数为std::string时,如果容器主键类型为KeyString,可能导致每次查找都要
                将std::string转化为KeyString,需要多做一次转化步骤,即内存分配
                如何避免这种多余的性能损耗?
                1.移除长度数据编码,使得获取长度的时间复杂度为O(N)
                2.然后构造一个临时的KeyString子类,伪造一个指针,析构的时候,将指针清空
*/
class S_CORE_EXPORT KeyString {
  typedef KeyString ThisType;

 public:
  enum : uint64_t {
    HighBit = 0x80,  // 首个字符的最高位
    MostBitFlag =
        (sizeof(uintptr_t) == 4 ? 0x80000000 : 0x8000000000000000LL),  // 最高位
    LowBitMask = 0x7F,  // 首个字符的第七位掩码
    TinyLength = 1 << 7,  // 短字符串长度,超过此值需要用2个字符存储长度
    MaxLength = (1 << 15) - 1  // 最大字符串长度,长于此值截断
  };

 protected:
  union {
    const char* m_data;  //
    char m_raw[4];       //
  };

 public:
  ~KeyString();
  KeyString();
  KeyString(const char* str);
  KeyString(const char* str, int len);
  KeyString(const std::string& str);
  KeyString(const ThisType& str);
  KeyString(ThisType&& str);
  KeyString& operator=(ThisType&& str);
  KeyString& operator=(const char* str);
  KeyString& operator=(const KeyString& str);
  KeyString& operator+=(const ThisType& str);
  KeyString& operator+=(const char* str);
  const char* c_str() const;

  void Reset() { destroy(); }
  int size() const;
  int bytes() const;
  bool empty() const { return size() <= 0; }
  operator const char*() const { return c_str(); }
  bool operator<(const ThisType& str) const {
    return scompare(c_str(), size(), str.c_str(), str.size()) < 0;
  }
  bool operator<(const char* str) const {
    return scompare(c_str(), size(), str, str ? strlen(str) : 0) < 0;
  }
  bool operator>(const char* str) const {
    return scompare(c_str(), size(), str, str ? strlen(str) : 0) > 0;
  }
  bool operator>(const ThisType& str) const {
    return scompare(c_str(), size(), str.c_str(), str.size()) > 0;
  }
  bool operator==(const ThisType& str) const;
  bool operator==(const char* str) const;
  bool assign_plus(const char* str, int len, const char* post, int postLen);
  bool assign(const char* str, int len);

 protected:
  static inline int scompare(const char* self, int slen, const char* str,
                             int len) {
    if (slen <= 0 && len <= 0)
      return 0;
    else if (slen <= 0)
      return -1;
    else if (len <= 0)
      return 1;
    return strcmp(self, str);
  }
  inline bool istiny() const {
    return m_data != nullptr &&
           !(MostBitFlag &
             (static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(m_data))));
  }
  void destroy();
  bool haspointer() const;
  inline const char* pointer() const {
    return (const char*)((static_cast<uintptr_t>(
                             reinterpret_cast<uintptr_t>(m_data))) &
                         ~MostBitFlag);
  }
  inline void set_pointer(const char* ptr) {
    m_data = (const char*)((static_cast<uintptr_t>(
                               reinterpret_cast<uintptr_t>(ptr))) |
                           MostBitFlag);
  }
  inline void set_length(char* data, int total) const {
    if (total >= TinyLength) {
      data[0] = (total >> 8) | 0x80;
      data[1] = total & 0x00ff;  // 低8位
    } else
      data[0] = total;
  }
};
}  // namespace base
}  // namespace qb
